package com.smile.frame.workflow.flowable.demo.service.impl;

import cn.hutool.core.util.StrUtil;
import com.smile.frame.workflow.flowable.demo.constants.BpmnModelConstants;
import com.smile.frame.workflow.flowable.demo.service.BpmProcessDefinitionService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author LGC
 */
@Slf4j
@Service
public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionService {
    @Resource
    private RepositoryService repositoryService;

    @Override
    public String createProcessDefinition(Model model, byte[] bpmnBytes) {
        // 创建 Deployment 部署
        log.info("于流程模型，部署创建流程定义");
        Deployment deploy = repositoryService.createDeployment()
                .key(model.getKey()).name(model.getName()).category(model.getCategory())
                .addBytes(model.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, bpmnBytes)
                .tenantId("")
                .disableSchemaValidation() // 禁用 XML Schema 验证，因为有自定义的属性
                .deploy();
        // 根据部署ID，获取流程定义
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId()).singleResult();
        // 设置流程定义分类
        repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory());
        // 注意 1，ProcessDefinition 的 key 和 name 是通过 BPMN 中的 <bpmn2:process /> 的 id 和 name 决定
        // 注意 2，目前该项目的设计上，需要保证 Model、Deployment、ProcessDefinition 使用相同的 key，保证关联性。
        if (!Objects.equals(definition.getKey(), model.getKey())) {
            throw new RuntimeException(String.format("流程定义的key期望是(%s)，当前是(%s)，请修改 BPMN 流程图", model.getKey(), definition.getKey()));
        }
        if (!Objects.equals(definition.getName(), model.getName())) {
            throw new RuntimeException(String.format("流程定义的name期望是(%s)，当前是(%s)，请修改 BPMN 流程图", model.getKey(), definition.getKey()));
        }

        return definition.getId();
    }

    @Override
    public void updateProcessDefinitionState(String processDefinitionId, Integer state) {

        // 激活
        if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) {
            repositoryService.activateProcessDefinitionById(processDefinitionId, false, null);
            return;
        }
        // 挂起
        if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) {
            // suspendProcessInstances = false，进行中的任务，不进行挂起。
            // 原因：只要新的流程不允许发起即可，老流程继续可以执行。
            repositoryService.suspendProcessDefinitionById(processDefinitionId, false, null);
            return;
        }
        log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", processDefinitionId, state);
    }

    @Override
    public ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId) {
        if (StrUtil.isEmpty(deploymentId)) {
            return null;
        }
        return repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
    }

}
